package com.fumin.service;

import com.fumin.dao.SysAclMapper;
import com.fumin.dao.SysAclModuleMapper;
import com.fumin.dao.SysDeptMapper;
import com.fumin.dto.AclDTO;
import com.fumin.dto.AclModuleLevelDto;
import com.fumin.dto.DeptLevelDto;
import com.fumin.model.SysAcl;
import com.fumin.model.SysAclModule;
import com.fumin.model.SysDept;
import com.fumin.util.LevelUtil;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * 组装前台用到的tree结构对象
 * @Author xiayuxuanmin
 * @Date 2019/10/22
 * @Description
 */
@Service
public class SysTreeService {

    @Resource
    private SysDeptMapper sysDeptMapper;
    @Resource
    private SysAclModuleMapper sysAclModuleMapper;
    @Resource
    private SysCoreService sysCoreService;
    @Resource
    private SysAclMapper sysAclMapper;

    /**
     * 获取用户所有的权限组成一棵树
     * @param userId
     * @return
     */
    public List<AclModuleLevelDto> userAclTree(int userId){
        //1.获取当前用户已经分配的权限点
        List<SysAcl> userAclList = sysCoreService.getUserAclList(userId);
    //4.生成AclDTO的集合
        List<AclDTO> aclDTOList = Lists.newArrayList();
        for(SysAcl sysAcl:userAclList){
            AclDTO aclDTO = AclDTO.adapt(sysAcl);
            aclDTO.setHasAcl(true);//根据用户查找权限,那么用户肯定具有该权限
             aclDTO.setChecked(true);//也肯定是选中的
            aclDTOList.add(aclDTO);
        }
        return aclListToTree(aclDTOList);
    }

    /**
     *  获取指定角色分配的所有权限组成的树结构
     *  返回 以当前用户已经分配的权限点和指定权限的权限点的大集合
     * @param roleId
     * @return
     */
    public List<AclModuleLevelDto> roleTree(int roleId){
        //1.获取当前用户已经分配的权限点
        List<SysAcl> userAclList = sysCoreService.getCurrentUserAclList();
        //2.当前角色分配的权限点
        List<SysAcl> roleAclList = sysCoreService.getRoleAclList(roleId);

        //获取当前用户已经分配的权限点的ID集合
        //利用JAVA8循环userAclList,提取该集合中的每个对象的ID属性,组成一个集合
        Set<Integer> userAclIdSet = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        //获取当前角色分配的权限点的ID集合
        Set<Integer> roleAclIdSet = roleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        /*//3.取两个权限点ID集合的进行合并(这个不再取并集,而是取出所有的权限点的List集合)
        Set<SysAcl> aclSet = new HashSet<>(roleAclList);
        aclSet.addAll(userAclList);*/
        //获取当前系统所有的权限点列表
        List<SysAcl> allAclList = sysAclMapper.getAll();

        //4.生成AclDTO的集合
        List<AclDTO> aclDTOList = Lists.newArrayList();
        for(SysAcl sysAcl:/*aclSet*/allAclList){
            AclDTO aclDTO = AclDTO.adapt(sysAcl);
            if (userAclIdSet.contains(aclDTO.getId())) {
                aclDTO.setHasAcl(true);
            }
            if (roleAclIdSet.contains(aclDTO.getId())) {
                aclDTO.setChecked(true);
            }
            aclDTOList.add(aclDTO);
        }
        return aclListToTree(aclDTOList);
    }

    /**
     * 获取权限的树结构,把权限点挂靠在对应的权限模块上面
     * @param aclDtoList
     * @return
     */
    public List<AclModuleLevelDto> aclListToTree(List<AclDTO> aclDtoList){
        if (CollectionUtils.isEmpty(aclDtoList)) {
            return Lists.newArrayList();
        }
        //获取所有权限模块的树结构
        List<AclModuleLevelDto> aclModuleLevelList = adlModuleTree();
        //获取每个权限模块下面的权限点的list集合构成的Map数据
        Multimap<Integer,AclDTO> moduleIdAclMap = ArrayListMultimap.create();
        for (AclDTO aclDTO : aclDtoList) {
            if(aclDTO.getStatus() == 1){
                //如果权限点可用(即权限点有效)
                moduleIdAclMap.put(aclDTO.getAclModuleId(),aclDTO);
            }
        }
        bindAclsWithOrder(aclModuleLevelList,moduleIdAclMap);
        return aclModuleLevelList;
    }

    /**
     * 把权限点绑定到权限模块树上面
     * @param aclModuleLevelList 权限模块集合
     * @param moduleIdAclMap 权限点的集合
     */
    public void bindAclsWithOrder(List<AclModuleLevelDto> aclModuleLevelList,Multimap<Integer,AclDTO> moduleIdAclMap){
        if (CollectionUtils.isEmpty(aclModuleLevelList)) {
            return;
        }
        for (AclModuleLevelDto dto : aclModuleLevelList) {
            //获取权限模块下的所有权限点
            List<AclDTO> aclDTOS = ( List<AclDTO>)moduleIdAclMap.get(dto.getId());
            if (CollectionUtils.isNotEmpty(aclDTOS)) {
                //如果权限模块下面有可用的权限点,那么把权限点都绑定到对应的权限模块上
                //对权限点进行排序
                Collections.sort(aclDTOS,aclSeqComparator);
                //把已经排好序的权限点的列表放到权限模块上面去
                dto.setAclList(aclDTOS);
            }
            //递归调用绑定权限点到权限模块上面(即在子权限模块上面把权限点绑定过来)
            bindAclsWithOrder(dto.getAclModuleList(),moduleIdAclMap);
        }
    }

    /**
     * 返回权限模块的树结构的数据
     * @return
     */
    public List<AclModuleLevelDto> adlModuleTree(){
        List<SysAclModule> aclModuleList = sysAclModuleMapper.getAllDept();
        //包装为dto对象
        List<AclModuleLevelDto> dtoList = Lists.newArrayList();
        for (SysAclModule aclModule : aclModuleList) {
            AclModuleLevelDto dto = AclModuleLevelDto.adapt(aclModule);
            dtoList.add(dto);
        }
        return aclModuleListToTree(dtoList);
    }

    /**
     * 组装TREE结构数据
     * @param aclModuleLevelList
     * @return
     */
    public List<AclModuleLevelDto> aclModuleListToTree(List<AclModuleLevelDto> aclModuleLevelList){
        if (CollectionUtils.isEmpty(aclModuleLevelList)) {
            return Lists.newArrayList();
        }
        //level ---> [dept1,dept2...],和我们以前的写法：Map<String,List<DeptLevelDto>> levelDtoMap = new HashMap<>()是一致的
        Multimap<String,AclModuleLevelDto> levelDtoMap = ArrayListMultimap.create();//推荐用
        List<AclModuleLevelDto> rootList = Lists.newArrayList();//所有的顶级节点,即level为0
        for (AclModuleLevelDto dto : aclModuleLevelList) {
            //把所有level相同的节点放在一个LIST中(即按照父节点分组...LEVEL为0的为一组;LEVEL为0.1的为一组,LEVEL为0.2的为一组)
            levelDtoMap.put(dto.getLevel(),dto);//这个dto会添加到list集合中
            if (dto.getLevel().equals(LevelUtil.ROOT)) {
                rootList.add(dto);
            }
        }
        //把ROOTLIST按照SEQ的升序排列
        Collections.sort(rootList, new Comparator<AclModuleLevelDto>() {
            public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        });
        //把ROOTLIST的每个节点的子节点递归排序
        transformAclModuleTree(rootList,LevelUtil.ROOT,levelDtoMap);//rootList的level为LevelUtil.ROOT,因为在找rootList中的每个节点的子节点的时候,会根据level为:(父节点level.父节点.id)
        return rootList;
    }

    /**
     * 组装树结构
     * 把指定level层级的deptLevelList，按照SEQ的升序排列
     * 首层：level:0 --->[0.1,0.2] //这两个节点的父节点都在同一个层级（LEVEL为0），但一个父节点的ID为1,一个父节点为ID为2，即LEVEL为顶级的节点有两个，一个ID为1,一个ID为2；
     * ID为1的节点下面有一个子节点，该子节点的LEVEL为：0.1；ID为2的节点下面有一个子节点，该子节点的LEVEL为：0.2；
     * level:0.1--->[0.11,0.12]
     * level:0.2--->[0.23,0.24]
     * @param doList AclModuleLevelDto
     * @param level doList 对应的层级
     * @param levelDtoMap level ---> [dept1,dept2...]的MAP对象
     */
    public void transformAclModuleTree(List<AclModuleLevelDto> doList,String level,Multimap<String,AclModuleLevelDto> levelDtoMap){
        for (int i = 0; i < doList.size(); i++) {
            //遍历集合的每个节点
            AclModuleLevelDto aclModuleLevelDto = doList.get(i);
            //获取当前节点deptLevelDto的子节点所在的层级
            String nextLevel = LevelUtil.calculateLevel(level, aclModuleLevelDto.getId());//level.id,即获取当前节点的子节点所在的层级
            List<AclModuleLevelDto> tempDeptList = (List)levelDtoMap.get(nextLevel);//获取当前节点的子节点的集合
            if (CollectionUtils.isNotEmpty(tempDeptList)) {
                //排序
                Collections.sort(tempDeptList,aclModuleSeqComparator);
                //设置下一层权限模块(即子节点)
                aclModuleLevelDto.setAclModuleList(tempDeptList);
                //组织子节点的树结构
                transformAclModuleTree(tempDeptList,nextLevel,levelDtoMap);
            }
        }
    }

    /**
     * 返回部门的树结构的数据
     * @return
     */
    public List<DeptLevelDto> deptTree(){
        List<SysDept> deptList = sysDeptMapper.getAllDept();
        //包装为dto对象
        List<DeptLevelDto> dtoList = Lists.newArrayList();
        for (SysDept dept : deptList) {
            DeptLevelDto dto = DeptLevelDto.adapt(dept);
            dtoList.add(dto);
        }
        return deptListToTree(dtoList);
    }

    /**
     * 组装TREE结构数据
     * @param deptLevelList
     * @return
     */
    public List<DeptLevelDto> deptListToTree(List<DeptLevelDto> deptLevelList){
        if (CollectionUtils.isEmpty(deptLevelList)) {
            return Lists.newArrayList();
        }
        //level ---> [dept1,dept2...],和我们以前的写法：Map<String,List<DeptLevelDto>> levelDtoMap = new HashMap<>()是一致的
        Multimap<String,DeptLevelDto> levelDtoMap = ArrayListMultimap.create();//推荐用
        List<DeptLevelDto> rootList = Lists.newArrayList();//所有的顶级节点,即level为0
        for (DeptLevelDto dto : deptLevelList) {
            //把所有level相同的节点放在一个LIST中(即按照父节点分组...LEVEL为0的为一组;LEVEL为0.1的为一组,LEVEL为0.2的为一组)
            levelDtoMap.put(dto.getLevel(),dto);//这个dto会添加到list集合中
            if (dto.getLevel().equals(LevelUtil.ROOT)) {
                rootList.add(dto);
            }
        }
        //把ROOTLIST按照SEQ的升序排列
        Collections.sort(rootList, new Comparator<DeptLevelDto>() {
            public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        });
        //把ROOTLIST的每个节点的子节点递归排序
        transformDeptTree(rootList,LevelUtil.ROOT,levelDtoMap);//rootList的level为LevelUtil.ROOT,因为在找rootList中的每个节点的子节点的时候,会根据level为:(父节点level.父节点.id)
        return rootList;
    }

    /**
     * 组装树结构
     * 把指定level层级的deptLevelList，按照SEQ的升序排列
     * 首层：level:0 --->[0.1,0.2] //这两个节点的父节点都在同一个层级（LEVEL为0），但一个父节点的ID为1,一个父节点为ID为2，即LEVEL为顶级的节点有两个，一个ID为1,一个ID为2；
     * ID为1的节点下面有一个子节点，该子节点的LEVEL为：0.1；ID为2的节点下面有一个子节点，该子节点的LEVEL为：0.2；
     * level:0.1--->[0.11,0.12]
     * level:0.2--->[0.23,0.24]
     * @param deptLevelList 所在LEVEL层级的DeptLevelDto的集合
     * @param level deptLevelList 对应的层级
     * @param levelDtoMap level ---> [dept1,dept2...]的MAP对象
     */
    public void transformDeptTree(List<DeptLevelDto> deptLevelList,String level,Multimap<String,DeptLevelDto> levelDtoMap){
        for (int i = 0; i < deptLevelList.size(); i++) {
            //遍历集合的每个节点
            DeptLevelDto deptLevelDto = deptLevelList.get(i);
            //获取当前节点deptLevelDto的子节点所在的层级
            String nextLevel = LevelUtil.calculateLevel(level, deptLevelDto.getId());//level.id,即获取当前节点的子节点所在的层级
            List<DeptLevelDto> tempDeptList = (List)levelDtoMap.get(nextLevel);//获取当前节点的子节点的集合
            if (CollectionUtils.isNotEmpty(tempDeptList)) {
                //排序
                Collections.sort(tempDeptList,deptSeqComparator);
                //设置下一层部门(即子节点)
                deptLevelDto.setDeptList(tempDeptList);
                //组织子节点的树结构
                transformDeptTree(tempDeptList,nextLevel,levelDtoMap);
            }
        }
    }

    public Comparator<DeptLevelDto> deptSeqComparator = new Comparator<DeptLevelDto>() {
        public int compare(DeptLevelDto o1, DeptLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    public Comparator<AclModuleLevelDto> aclModuleSeqComparator = new Comparator<AclModuleLevelDto>() {
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    public Comparator<AclDTO> aclSeqComparator = new Comparator<AclDTO>(){
        public int compare(AclDTO o1, AclDTO o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };
}
